package Schedule::Chronic::Distributed::Command;

=head1 NAME

Schedule::Chronic::Distributed::TaskTimes - Task Times

=head1 SYNOPSIS

use Schedule::Chronic::Distributed::TaskTimes;

.. TODO..

=head1 DESCRIPTION

Task Requirement class, maps tasks to requirements and required levels.

=head1 METHODS

=head2 ACCESSORS

=over

=item id

=item name

=item path

=item filename

=item description

=item category

=item type

=back

=head2 run

Object method to run the command on this node.

requires task object, and optional path as arguments.

=cut

use strict;

use base qw(Schedule::Chronic::Distributed::DBI);

Schedule::Chronic::Distributed::Command->table('command');
__PACKAGE__->sequence('command_id_seq');
Schedule::Chronic::Distributed::Command->columns(All => qw/id name path filename description category type/);
Schedule::Chronic::Distributed::Command->columns(Primary => 'id');

__PACKAGE__->has_a(category => 'Schedule::Chronic::Distributed::Category');
Schedule::Chronic::Distributed::Command->has_many(tasks => 'Schedule::Chronic::Distributed::Task');

sub run {
  my $self = shift;
  my $task = shift;
  my $path = shift || $self->path;

  local @_ = split(/\s*\,\s*/,$task->command_arguments);

  warn "command running : ",$task->name, ' ', $task->id,"\n";
  my $ok = 0;
  my $error;
  my $stdout_filename = "/tmp/schedule_task_".$$.".stdout";
  my $stderr_filename = "/tmp/schedule_task_".$$.".stderr";

  if ($self->type eq 'perl') {
    warn "running as perl\n";
    open(OLD_STDERR,">&STDERR") or warn "Failed to save STDERR";
    open(STDERR,">$stderr_filename") or warn "Failed to redirect STDERR";
    open(OLD_STDOUT,">&STDOUT") or warn "Failed to save STDOUT";
    open(STDOUT,">$stdout_filename") or warn "Failed to redirect STDOUT";

    print "$$\n";
    warn "$$\n";

    my $filename = ( $path ) ? "$path/".$self->filename : $self->filename;
    $filename =~ s|\/\/|\/|g;
    print OLD_STDERR "filename : $filename\n";
    eval {
	*real_exit = *CORE::GLOBAL::exit;
	*CORE::GLOBAL::exit = sub { warn localtime() ." pid : $$ attempted to exit! caller : ", join(', ',caller()),"\n"; };
	$ok = do "$filename";
	$error = "couldn't parse $filename: $@" if $@;
	$error = "couldn't do $filename: $!"    unless defined $ok;
	$error = "couldn't run $filename"       unless $ok;
	*CORE::GLOBAL::exit = *real_exit;
    };
    if ($error){
      warn "error : $error\n" ;
    } else {
      $ok = 1;
    }
    open(STDOUT,">&OLD_STDOUT") or warn "Failed to restore STDOUT";
    open(STDERR,">&OLD_STDERR") or warn "Failed to restore STDERR";
    $error = "problem doing $filename: $@" if $@;
#    warn "done ok : $ok\n";
  } else {
    my $commandline = ( $path ) ? "$path/".$self->filename : $self->filename;
    $commandline =~ s|\/+|\/|g;
    my @args = ($commandline, grep ($_,@_),);
#    warn "running as system command :\n",join(' ',@args),"\n";
    open(OLD_STDERR,">&STDERR") or warn "Failed to save STDERR";
    open(STDERR,">$stderr_filename") or warn "Failed to redirect STDERR";
    open(OLD_STDOUT,">&STDOUT") or warn "Failed to save STDOUT";
    open(STDOUT,">$stdout_filename") or warn "Failed to redirect STDOUT";

    print "$$\n";
    warn "$$\n";

    my $exit_value = system(@args);

    open(STDOUT,">&OLD_STDOUT") or warn "Failed to restore STDOUT";
    open(STDERR,">&OLD_STDERR") or warn "Failed to restore STDERR";

    $ok = 1;
    unless ($exit_value == 0) {
      $ok = 0;
      if ($? == -1) {
	$error =  "command '$commandline' failed to run : $!\n";
      }
      elsif ($? & 127) {
	$error =   sprintf "command '$commandline' died with signal %d, %s coredump\n",
	  ($? & 127),  ($? & 128) ? 'with' : 'without';
      }
      else {
	$error = sprintf "command '$commandline' exited with value %d\n", $? >> 8;
      }
    }
  }

  warn "command finished : ",$task->name, ' ', $task->id," ok : $ok -- error : $error\n";
  return ($ok,$error);
}


1;

__END__

=head1 SEE ALSO

Schedule::Chronic::Distributed

Schedule::Chronic::Distributed::Task

=head1 AUTHOR

aaron trevena, E<lt>aaron.trevena@gmail.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2006 by Aaron Trevena

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.5 or,
at your option, any later version of Perl 5 you may have available.

=cut
